/*
* File: IFdEventInterface.h
* Copyright (c) 2010. Silviu Caragea <silviu@intelliproject.net>
* Created on September 8, 2010, 10:14 PM
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*  1.Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*  2.Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*  3.All advertising materials mentioning features or use of this software
*    must display the following acknowledgement:
*       This product includes software developed by the University of
*       California, Berkeley and its contributors.
*  4.Neither the name of the University nor the names of its contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef IFdEventInterface_H
#define	IFdEventInterface_H

#include <assert.h>
#include <stdlib.h>

#include "../config.h"
#include "../utils/CLogger.h"
#include "../utils/basic_types.h"

#ifdef USE_STL_MAP
    #include <map>
#endif

/*events*/

namespace litevent
{

#define FDEVENT_IN     SHIFT_LEFT(1,0)    /* There is data to read. */
#define FDEVENT_PRI    SHIFT_LEFT(1,1)    /* There is urgent data to read. */
#define FDEVENT_OUT    SHIFT_LEFT(1,2)    /* Writing now will not block. */
#define FDEVENT_ERR    SHIFT_LEFT(1,3)    /* Error condition. */
#define FDEVENT_HUP    SHIFT_LEFT(1,4)    /* Hung up. */
#define FDEVENT_NVAL   SHIFT_LEFT(1,5)    /* Invalid polling request. */

enum EnumEventHandlerType
{
    EnumEventHandlerTypeUnset = -1,
    EnumEventHandlerTypeSelect,
    EnumEventHandlerTypePoll,
    EnumEventHandlerTypeKqueue,
    EnumEventHandlerTypeEpoll,
    EnumEventHandlerTypeDevPoll
};

struct EventMothodSignature
{
    const char *name;
    EnumEventHandlerType type;
};

typedef void (*fd_event_handler)(int fd, void *ctx, int revents);

struct fdnode
{
    fd_event_handler handler;
    SignalEvent *OnEvent;

    void *ctx;
    int fd;
    int events;
    int nodeIndex;
};

#ifdef USE_STL_MAP    
    struct compareFdnode{bool operator()(int k1, int k2) const{return k1 < k2;}};
    typedef std::map<int, struct fdnode*,compareFdnode> FileDescriptorMap;
#endif

class IFdEventInterface
{

public:
  
    explicit IFdEventInterface(size_t maxfds);
    virtual ~IFdEventInterface();
    
    template <class K> int fdRegisterEvent(int fd, void*ctx, K *obj, void(K::*method)(int, void*,int) );
    
    int fdRegisterEvent(int fd, fd_event_handler handler, void *ctx);
    void fdUnregisterEvent(int fd);
    inline int isfdRegistered(int fd);

    int  fdDeleteEvent( int fd);
    void fdSetEvent(int fd, int events);

    inline int fdPoll(int timeoutMs);
    inline int fdGetReturnedEvents(size_t node_index);
    inline int fdGetFileDescriptor(size_t node_index);
    inline int fdGetNextFileDescriptor(int node_index);
    inline fd_event_handler fdGetHandler(int fd);
    inline SignalEvent * fdGetSignalSlot(int fd);

    inline void* fdGetContext(int fd);
    inline size_t getWatchedEvents();

    virtual int reset() {return 0;}; /*fork*/

    static int makeSocketNonBlock(int fd);    

protected:
    
    virtual int deleteEvent(int fd_node, int fd ) {return -1;}
    virtual int setEvent(int fd_node , int fd, int events) {return -1;} 
    virtual int getEventNextFileDescriptor(int node) {return -1;}

    /*abstract*/
    
    virtual int getEventRevent(size_t node) = 0;
    virtual int getEventFileDescriptor(size_t node) =0;
    virtual int poll(int timeoutMs) =0;
       
#ifdef USE_STL_MAP    
    FileDescriptorMap fdMap;
#else
    fdnode **fdarray;
#endif
    
    size_t maxfds;
    size_t watchedEvents;

private:
    inline fdnode* _getNode(int fd);
    DISALLOW_IMPLICIT_CONSTRUCTORS(IFdEventInterface);
};

}

#endif	/* IFdEventInterface_H */


